docker源码解析(一)dockerd服务的启动 您所在的位置:网站首页 docker 源代码解析 docker源码解析(一)dockerd服务的启动

docker源码解析(一)dockerd服务的启动

2024-07-16 12:41| 来源: 网络整理| 查看: 265

docker源码解析(一) 部分参数默认值main函数入口newDaemonCommand()函数runDaemon()函数Windows平台linux平台 daemonCli.start()函数newDaemon()函数containerd.New()d.restore()volumesservice.NewVolumeService()

本文源码基于docker20.10.8。文中机器安装的docker代码版本为docker20.10.0。 本文的计算机环境是centos-8。因此,不介绍Windows平台的docker。 docker源码地址

参考文献 1. docker的初始化——by lovenashbest-简书 Docker - NewDaemon源码分析——by ETIN-知乎 docker 源码分析NewDaemon 函数——by arwen_spy-博客园

部分参数默认值 Config.Root /var/lib/docker Config.ExecRoot /var/run/docker Config.Pidfile /var/run/docker.pid imageRoot /var/lib/docker/image/文件系统(linux为overlay2)/ main函数入口

代码位置:/moby/cmd/dockerd/docker.go:

func main() { if reexec.Init() { return } // initial log formatting; this setting is updated after the daemon configuration is loaded. logrus.SetFormatter(&logrus.TextFormatter{ TimestampFormat: jsonmessage.RFC3339NanoFixed, FullTimestamp: true, }) // Set terminal emulation based on platform as required. _, stdout, stderr := term.StdStreams() initLogging(stdout, stderr) onError := func(err error) { fmt.Fprintf(stderr, "%s\n", err) os.Exit(1) } cmd, err := newDaemonCommand() if err != nil { onError(err) } cmd.SetOutput(stdout) if err := cmd.Execute(); err != nil { onError(err) } }

首先判断reexec.Init()方法的返回值,如果是真,则直接退出运行,否则继续执行。由于在docker运行之前,没有任何initializer注册,所以这段代码执行的返回值为假。

随后调用newDaemonCommand()函数,启动Daemon。

newDaemonCommand()函数

代码路径:/moby/cmd/dockerd/docker.go

func newDaemonCommand() (*cobra.Command, error) { opts := newDaemonOptions(config.New()) cmd := &cobra.Command{ Use: "dockerd [OPTIONS]", Short: "A self-sufficient runtime for containers.", SilenceUsage: true, SilenceErrors: true, Args: cli.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { opts.flags = cmd.Flags() return runDaemon(opts) }, DisableFlagsInUseLine: true, Version: fmt.Sprintf("%s, build %s", dockerversion.Version, dockerversion.GitCommit), } cli.SetupRootCommand(cmd) flags := cmd.Flags() flags.BoolP("version", "v", false, "Print version information and quit") defaultDaemonConfigFile, err := getDefaultDaemonConfigFile() if err != nil { return nil, err } flags.StringVar(&opts.configFile, "config-file", defaultDaemonConfigFile, "Daemon configuration file") opts.InstallFlags(flags) if err := installConfigFlags(opts.daemonConfig, flags); err != nil { return nil, err } installServiceFlags(flags) return cmd, nil }

首先调用newDaemonOptions()创建flag参数。

然后调用runDaemon()函数。

runDaemon()函数 Windows平台

Windows平台,代码路径:/moby/cmd/dockerd/docker_windows.go

func runDaemon(opts *daemonOptions) error { daemonCli := NewDaemonCli() // On Windows, this may be launching as a service or with an option to // register the service. stop, runAsService, err := initService(daemonCli) if err != nil { logrus.Fatal(err) } if stop { return nil } // Windows specific settings as these are not defaulted. if opts.configFile == "" { opts.configFile = filepath.Join(opts.daemonConfig.Root, `config\daemon.json`) } if runAsService { // If Windows SCM manages the service - no need for PID files opts.daemonConfig.Pidfile = "" } else if opts.daemonConfig.Pidfile == "" { opts.daemonConfig.Pidfile = filepath.Join(opts.daemonConfig.Root, "docker.pid") } err = daemonCli.start(opts) notifyShutdown(err) return err } linux平台

代码路径:/moby/cmd/dockerd/docker_unix.go

func runDaemon(opts *daemonOptions) error { daemonCli := NewDaemonCli() return daemonCli.start(opts) }

代码路径:/moby/cmd/dockerd/daemon.go

首先调用NewDaemonCli()申请了一个结构体实例。

// NewDaemonCli returns a daemon CLI func NewDaemonCli() *DaemonCli { return &DaemonCli{} }

随后调用start()函数。

daemonCli.start()函数

代码路径:/moby/cmd/dockerd/daemon.go

func (cli *DaemonCli) start(opts *daemonOptions) (err error) { opts.SetDefaultOptions(opts.flags) //TLS加密配置 loadDaemonCliConfig(opts) //配置docker信息 configureDaemonLogs(cli.Config) //日志等级配置 setDefaultUmask() //设置umask默认权限0022,对应文件目录权限为0755->即用户具有读/写/执行权限,组用户和其它用户具有读写权限; // Create the daemon root before we create ANY other files (PID, or migrate keys) // to ensure the appropriate ACL is set (particularly relevant on Windows) daemon.CreateDaemonRoot(cli.Config) //创建root路径 system.MkdirAll(cli.Config.ExecRoot, 0700)// 创建exec进去的路径 pf, err := pidfile.New(cli.Pidfile) //process ID if cli.Config.IsRootless() { // Set sticky bit if XDG_RUNTIME_DIR is set && the file is actually under XDG_RUNTIME_DIR StickRuntimeDirContents(potentiallyUnderRuntimeDir)//设置XDR_runtime路径 newAPIServerConfig(cli) //设置APIserver配置 apiserver.New(serverConfig) //创建一个apiserver对象 loadListeners(cli, serverConfig) //配置监听hosts //默认的host // tcp://127.0.0.1:2376 TLS // tcp://127:0.0.1:2375 HTTP(没有使用) // unix://runtime目录/var/run/docker.sock linux如果不使用TLS,使用这个,需要获取runtime目录。 // unix:///var/run/docker.sock Windows如果不使用TLS,则使用这个 context.WithCancel(context.Background()) // cli.initContainerD(ctx) //初始化containerd defer waitForContainerDShutdown(10 * time.Second) //退出以后,10s时间内没有响应则强制结束。 // Notify that the API is active, but before daemon is set up. preNotifySystem() //函数空? pluginStore := plugin.NewStore() //创建plugin仓库。插件仓库 cli.initMiddlewares(cli.api, serverConfig, pluginStore)// //docker-experimental //docker version //配置为每个请求添加的cors头。 //authorization middleware //重点!!! daemon.NewDaemon(ctx, cli.Config, pluginStore) //通过config, registry, containerd, pluginStore来真正创建了daemon d.StoreHosts(hosts) //127.0.0.1:2376等一系列。 //把定义的host map数据结构中的value值设置为true,表示开始监听。 // validate after NewDaemon has restored enabled plugins. Don't change order. validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore)// cli.d = d cli.startMetricsServer(cli.Config.MetricsAddress) //metrics地址 //对应daemon.json文件中的key值为:"metrics-addr" //需要在experiment模式下才能使用。 //不懂这个地址是用来干什么的。 createAndStartCluster(cli, d) //创建并开始cluster //swarm // Restart all autostart containers which has a swarm endpoint // and is not yet running now that we have successfully // initialized the cluster. d.RestartSwarmContainers() //重启swarm容器。 //重新启动所有具有swarm端点并且在我们成功初始化集群后尚未运行的autostart容器。 newRouterOptions(cli.Config, d) //配置router //不懂 initRouter(routerOptions) //初始化router //不懂 // ProcessClusterNotifications gets changes from store and add them to event list go d.ProcessClusterNotifications(ctx, c.GetWatchStream())//处理cluster集群信号。 //ProcessClusterNotifications从存储中获取更改并将其添加到事件列表中 cli.setupConfigReloadTrap() //SIGHUP信号的时候,reload config。 // The serve API routine never exits unless an error occurs // We need to start it as a goroutine and wait on it so // daemon doesn't exit serveAPIWait := make(chan error) go cli.api.Wait(serveAPIWait) //API server 开始监听 // after the daemon is done setting up we can notify systemd api notifySystem() //空函数? // Daemon is fully initialized and handling API traffic // Wait for serve API to complete errAPI := setDefaultMtu(config) //设置默认的MTU。默认Mtu为1500 registry.NewService(config.ServiceOptions) //生成registry Service实例。 // Ensure that we have a correct root key limit for launching containers. ModifyRootKeyLimit() //和能启动的容器数量有关 //ModifyRootKeyLimit检查根密钥限制是否设置为至少1000000,并将其与分配给密钥的maxbytes一起以25:1的倍率更改为该限制。 //不懂 // Ensure we have compatible and valid configuration options verifyDaemonSettings(config) //配置信息校验 // Do we have a disabled network? isBridgeNetworkDisabled(config) //判断网桥是否禁用 // Setup the resolv.conf //如果未指定,setupResolvConf将设置相应的resolv.conf文件。 //当systemd resolved运行时,默认的/etc/resolv.conf指向localhost。在本例中,获取位于不同路径中的备用配置文件,以便容器可以使用它。 //在所有其他情况下,返回默认值。 setupResolvConf(config) //设置resolv.conf配置文件位置,默认是/etc/resolv.conf // Verify the platform is supported as a daemon if !platformSupported { //检查系统是否支持 - platformSupported 为系统常量。在代码中为常量true return nil, errSystemNotSupported } // Validate platform-specific requirements if err := checkSystem(); err != nil { //系统平台校验,内核版本是否满足要求 //docker 1.11以上不再支持3.4以下的内核版本。 return nil, err } setupRemappedRoot(config) //将容器内的用户映射为宿主机上的普通用户。 idMapping.RootPair() //创建根uid,gid //上面两个语句完成映射。没看懂源码 setupDaemonProcess(config) // daemon进程其他设置:设置OOM Killer和MayDetachMounts // set up the tmpDir to use a canonical path prepareTempDir(config.Root, rootIDs) //准备临时文件夹 //prepareTempDir准备并返回用于临时文件的默认目录。如果它不存在,则创建它。如果存在,则删除其内容。 fileutils.ReadSymlinkedDirectory(tmp) //给tmp临时文件夹创建一个符号链接。 //ReadSymlinkedDirectory返回符号链接的目标目录。 //符号链接的目标可能不是文件。 if runtime.GOOS == "windows" { if _, err := os.Stat(realTmp); err != nil && os.IsNotExist(err) { if err := system.MkdirAll(realTmp, 0700); err != nil { return nil, fmt.Errorf("Unable to create the TempDir (%s): %s", realTmp, err) } } os.Setenv("TEMP", realTmp) os.Setenv("TMP", realTmp) } else { os.Setenv("TMPDIR", realTmp) } d := &Daemon{ configStore: config, PluginStore: pluginStore, startupDone: make(chan struct{}), } // Ensure the daemon is properly shutdown if there is a failure during // initialization defer func() { if err != nil { if err := d.Shutdown(); err != nil { logrus.Error(err) } } }() if err := d.setGenericResources(config); err != nil { return nil, err } // set up SIGUSR1 handler on Unix-like systems, or a Win32 global event // on Windows to dump Go routine stacks stackDumpDir := config.Root if execRoot := config.GetExecRoot(); execRoot != "" { stackDumpDir = execRoot } //Root directory for execution state files //execRoot是执行状态文件的根目录 d.setupDumpStackTrap(stackDumpDir) //配置docker的goroutine堆栈输出目录。注册SIGUSR1信号。 //在这个函数内注册的USR1信号,所以可以使用在命令行使用 kill -s USR1 $(pidof dockerd)来调取docker运行堆栈信息。 //如果execRoot不为空,则在execRoot目录下。(默认execRoot是/var/run/docker) //如果execRoot为空,则在Root目录下。(默认Root是/var/lib/docker) d.setupSeccompProfile() //设置linux内核的Seccomp,用于限制系统调用 //没懂 // Set the default isolation mode (only applicable on Windows) d.setDefaultIsolation() //设置默认隔离模式,仅windows下使用 configureMaxThreads(config) //linux下面设置最大线程 /proc/sys/kernel/threads-max // ensureDefaultAppArmorProfile does nothing if apparmor is disabled ensureDefaultAppArmorProfile() //代码中直接return nil? // 如果linux内核支持安全模块AppArmor(AppArmor允许系统管理员将每个程序与一个安全配置文件关联,从而限制程序的功能。 //简单的说,AppArmor是与SELinux类似的一个访问控制系统,通过它你可以指定程序可以读、写或运行哪些文件,是否可以打开网络端口等。),则判定是否加载,如加载则设置默认的profile daemonRepo := filepath.Join(config.Root, "containers") idtools.MkdirAllAndChown(daemonRepo, 0700, rootIDs)//创建/var/lib/docker/containers // Create the directory where we'll store the runtime scripts (i.e. in // order to support runtimeArgs) daemonRuntimes := filepath.Join(config.Root, "runtimes") system.MkdirAll(daemonRuntimes, 0700) //创建/var/lib/docker/runtimes //创建存储运行时脚本的目录(即为了支持runtimeArgs) d.loadRuntimes() //初始化runtime //windows系统中创建credentialspecs目录 if runtime.GOOS == "windows" { if err := system.MkdirAll(filepath.Join(config.Root, "credentialspecs"), 0); err != nil { return nil, err } } // On Windows we don't support the environment variable, or a user supplied graphdriver // as Windows has no choice in terms of which graphdrivers to use. It's a case of // running Windows containers on Windows - windowsfilter, running Linux containers on Windows, // lcow. Unix platforms however run a single graphdriver for all containers, and it can // be set through an environment variable, a daemon start parameter, or chosen through // initialization of the layerstore through driver priority order for example. d.graphDrivers = make(map[string]string) layerStores := make(map[string]layer.Store) if runtime.GOOS == "windows" { d.graphDrivers[runtime.GOOS] = "windowsfilter" //判断windows是否支持LCOW容器 if system.LCOWSupported() { d.graphDrivers["linux"] = "lcow" } } else { //linux driverName := os.Getenv("DOCKER_DRIVER")//设置graphdriver if driverName == "" { driverName = config.GraphDriver } else { logrus.Infof("Setting the storage driver from the $DOCKER_DRIVER environment variable (%s)", driverName) } d.graphDrivers[runtime.GOOS] = driverName // May still be empty. Layerstore init determines instead. } d.RegistryService = registryService logger.RegisterPluginGetter(d.PluginStore) //插件仓库 //不懂 d.listenMetricsSock() //监听metrics.sock //位置在 execRoot/metrics.sock // 详见: mount.Mount(sockPath, pluginSockPath, "none", "bind,ro") registerMetricsPluginCallback(d.PluginStore, metricsSockPath) // 没看懂 //以下为grpc gopts := []grpc.DialOption{ grpc.WithInsecure(), grpc.WithBackoffMaxDelay(3 * time.Second), grpc.WithDialer(dialer.Dialer), // TODO(stevvooe): We may need to allow configuration of this on the client. grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), } //创建containerdCli if config.ContainerdAddr != "" { d.containerdCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(config.ContainerdNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second)) if err != nil { return nil, errors.Wrapf(err, "failed to dial %q", config.ContainerdAddr) } } //创建pluginExec createPluginExec := func(m *plugin.Manager) (plugin.Executor, error) { var pluginCli *containerd.Client // Windows is not currently using containerd, keep the // client as nil if config.ContainerdAddr != "" { pluginCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(config.ContainerdPluginNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second)) if err != nil { return nil, errors.Wrapf(err, "failed to dial %q", config.ContainerdAddr) } } return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m) } //创建插件管理器 // Plugin system initialization should happen before restore. Do not change order. d.pluginManager, err = plugin.NewManager(plugin.ManagerConfig{ Root: filepath.Join(config.Root, "plugins"), ExecRoot: getPluginExecRoot(config.Root), Store: d.PluginStore, CreateExecutor: createPluginExec, RegistryService: registryService, LiveRestoreEnabled: config.LiveRestoreEnabled, LogPluginEvent: d.LogPluginEvent, // todo: make private AuthzMiddleware: config.AuthzMiddleware, }) d.setupDefaultLogConfig() //设置默认日志信息 //下面一大段都是在创建graphDrivers //首先,从config中读取GraphDriver。默认配置文件中,GraphDriver为空,GraphOptions也为空。 //其次,如果是空,则从环境变量DOCKER_DRIVER中读取grapDriver。 //最后,如果用户没有配置环境变量的DOCKER_DRIVER。则遍历系统的优先级存储系统 //linux中,priority = "btrfs,zfs,overlay2,aufs,overlay,devicemapper,vfs" //windows中,priority = "windowsfilter" //以上内容在newstoreFromOptions中的New函数中实现的。 //从driverStore创建layerStore。 for operatingSystem, gd := range d.graphDrivers { layerStores[operatingSystem], err = layer.NewStoreFromOptions(layer.StoreOptions{ Root: config.Root, MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"), GraphDriver: gd, GraphDriverOptions: config.GraphOptions, IDMapping: idMapping, PluginGetter: d.PluginStore, ExperimentalEnabled: config.Experimental, OS: operatingSystem, }) if err != nil { return nil, err } // As layerstore initialization may set the driver d.graphDrivers[operatingSystem] = layerStores[operatingSystem].DriverName() } //不懂为什么是overlay2而不是btrfs。 // Configure and validate the kernels security support. Note this is a Linux/FreeBSD // operation only, so it is safe to pass *just* the runtime OS graphdriver. configureKernelSecuritySupport(config, d.graphDrivers[runtime.GOOS]) //配置并验证内核安全支持。注意,这只是一个Linux/FreeBSD操作,因此传递*只是*运行时OS graphdriver是安全的。 //创建image根目录。/var/lib/docker/image imageRoot := filepath.Join(config.Root, "image", d.graphDrivers[runtime.GOOS]) //创建imagedb目录。/var/lib/docker/image/imagedb //imagedb目录是镜像数据库 //https://blog.csdn.net/weixin_39548163/article/details/118177663 image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb")) //创建仓库后端的文件系统 lgrMap := make(map[string]image.LayerGetReleaser) for os, ls := range layerStores { lgrMap[os] = ls } //在 imagedb 目录下新建两个目录,content/sha256和metadata/sha256,存储镜像内容和镜像元数据 image.NewImageStore(ifs, lgrMap) //创建镜像仓库实例 //配置Volume, local.New 创建目录 /var/lib/docker/volumes // Configure the volumes driver volumesservice.NewVolumeService(config.Root, d.PluginStore, rootIDs, d) //创建volume drive实例 //1.创建pluginstore实例。 //2.创建/var/lib/docker/volumes //3.创建/var/lib/docker/volumes/metadata.db(使用go.etcd.io/bbolt库操作的db)这个是volumeStore。 //4.返回volumeService实例。包含volumeStore和Store。volumeStore结构体中也有Store结构体。 //LoadOrCreateTrustKey尝试在给定路径加载libtrust密钥,否则将生成一个新路径 //TODO:这应该更多地使用libtrust.LoadOrCreateTrustKey,这可能需要重构或将此函数移动到libtrust中 loadOrCreateTrustKey(config.TrustKeyPath) //加载或者创建key,/etc/docker/key.json //创建trustdir,/var/lib/docker/trust trustDir := filepath.Join(config.Root, "trust") system.MkdirAll(trustDir, 0700) // We have a single tag/reference store for the daemon globally. However, it's // stored under the graphdriver. On host platforms which only support a single // container OS, but multiple selectable graphdrivers, this means depending on which // graphdriver is chosen, the global reference store is under there. For // platforms which support multiple container operating systems, this is slightly // more problematic as where does the global ref store get located? Fortunately, // for Windows, which is currently the only daemon supporting multiple container // operating systems, the list of graphdrivers available isn't user configurable. // For backwards compatibility, we just put it under the windowsfilter // directory regardless. filepath.Join(imageRoot, `repositories.json`) //创建refstore。位置。/var/lib/docker/image/overlay2/repositories.json //NewReferenceStore创建一个新的引用存储,绑定到一个文件路径,其中引用集以JSON格式序列化。 refstore.NewReferenceStore(refStoreLocation) //创建一个新的引用存储,绑定到一个文件路径上。 //创建TagStore。用于管理存储镜像的仓库列表,Repositories记录了镜像仓库的映射,referencesByIDCache记录了镜像ID和镜像全名的映射 //我们为守护进程全局提供了一个标记/引用存储。 //然而,它储存在graphdriver下面。在只支持单个容器操作系统,但支持多个可选graphdriver的主机平台上,这意味着根据选择的graphdriver,全局参考存储在其中。 //对于支持多个容器操作系统的平台,这稍微有点问题,因为全局ref存储在哪里? //幸运的是,对于目前唯一支持多容器操作系统的守护进程Windows,可用的GraphDriver列表不是用户可配置的。 //为了向后兼容,我们只是将其放在windowsfilter目录下。 // NewFSMetadataStore creates a new filesystem-based metadata store. dmetadata.NewFSMetadataStore(filepath.Join(imageRoot, "distribution"))//NewFSMetadataStore创建一个新的基于文件系统的元数据存储。 //返回的是文件位置。文件位置在/var/lib/image/overlay2/distribution // Discovery is only enabled when the daemon is launched with an address to advertise. When // initialized, the daemon is registered and we can store the discovery backend as it's read-only d.initDiscovery(config) //创建discoveryWatcher实例 //与cluster相关。需要cluster的advertiseaddress、clusterOpts和clusterStoure //只有在使用要公布的地址启动守护进程时,才会启用发现。初始化后,将注册守护进程,我们可以将发现后端存储为只读。 //不懂 sysInfo := sysinfo.New(false) //获取系统信息。存储在sysInfo结构体中 //获取系统信息, 包括cgroup、网络配置(网桥/iptables)和linux安全(AppArmor/Seccomp)等 // Check if Devices cgroup is mounted, it is hard requirement for container security, // on Linux. //New返回一个新的SysInfo,使用文件系统检测内核支持哪些功能。 //如果'quiet'为'false',则每当发生错误或存在错误配置时,日志中将打印警告。 //确保linux系统下,支持Cgroup if runtime.GOOS == "linux" && !sysInfo.CgroupDevicesEnabled { return nil, errors.New("Devices cgroup isn't mounted") } //以下大段内容均为赋值和初始化结构体。 d.ID = trustKey.PublicKey().KeyID() d.repository = daemonRepo d.containers = container.NewMemoryStore() if d.containersReplica, err = container.NewViewDB(); err != nil { return nil, err } d.execCommands = exec.NewStore() d.idIndex = truncindex.NewTruncIndex([]string{}) d.statsCollector = d.newStatsCollector(1 * time.Second) d.EventsService = events.New() d.root = config.Root d.idMapping = idMapping d.seccompEnabled = sysInfo.Seccomp d.apparmorEnabled = sysInfo.AppArmor d.linkIndex = newLinkIndex() // TODO: imageStore, distributionMetadataStore, and ReferenceStore are only // used above to run migration. They could be initialized in ImageService // if migration is called from daemon/images. layerStore might move as well. d.imageService = images.NewImageService(images.ImageServiceConfig{ ContainerStore: d.containers, DistributionMetadataStore: distributionMetadataStore, EventsService: d.EventsService, ImageStore: imageStore, LayerStores: layerStores, MaxConcurrentDownloads: *config.MaxConcurrentDownloads, MaxConcurrentUploads: *config.MaxConcurrentUploads, ReferenceStore: rs, RegistryService: registryService, TrustKey: trustKey, }) go d.execCommandGC() //新建协程清理容器不需要的命令 //每5分钟清理一次。 d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d) //创建和daemon相关的容器客户端libcontainerd //重点!!! //起一个新协程来监听事件。 //目前看到的事件有: //Create,Start,Exit,OOM,ExecAdded,ExecStarted,Paused,Resumned //与GRPC通信获取的event // 从 /var/lib/docker/containers 读取所有目录,下面的文件夹的名字就是容器的id, //存入 containers map[string]*container.Container 信息并注册如 daemon 结构体中。 //包括 start remove 操作 containers注册容器。注册信息都在内存中,启动daemon时需要重新进行注册 d.restore() close(d.startupDone) // FIXME: this method never returns an error info, _ := d.SystemInfo() //daemon运行的主机的配置信息。 engineInfo.WithValues( //配置信息 dockerversion.Version, dockerversion.GitCommit, info.Architecture, info.Driver, info.KernelVersion, info.OperatingSystem, info.OSType, info.OSVersion, info.ID, ).Set(1) engineCpus.Set(float64(info.NCPU)) engineMemory.Set(float64(info.MemTotal)) gd := "" for os, driver := range d.graphDrivers { if len(gd) > 0 { gd += ", " } gd += driver if len(d.graphDrivers) > 1 { gd = fmt.Sprintf("%s (%s)", gd, os) } } logrus.WithFields(logrus.Fields{ "version": dockerversion.Version, "commit": dockerversion.GitCommit, "graphdriver(s)": gd, }).Info("Docker daemon") return d, nil } containerd.New()

github.com/containerd/containerd/client.go:Line-79:New() 调用位置:docker/docker/daemon/daemon.go:Line-926:d.containerdCli, err = containerd.New

d.restore()

docker/docker/daemon/daemon.go:Line-207:restore() 调用位置:docker/docker/daemon/daemon.go:Line-1063:d.restore()

volumesservice.NewVolumeService()

docker/docker/volume/service/service.go 调用位置:docker/docker/daemon/daemon.go:Line-972:volumesservice.NewVolumeService()



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有